package com.weilive.core.protocol.protobuf;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.channel.Channel;

import com.google.protobuf.MessageLite;
import com.weilive.core.protocol.PacketCodec;
import com.weilive.core.protocol.protobuf.ProtobufPacket.PacketHead;
import com.weilive.core.session.SessionAccount;

public class ProtobufRequest {
	public final Integer id;
	public final Integer codec;
	public final String type;
	public final MessageLite data;
	public final ProtobufRequestHandler handler;
	public final Channel channel;

	public static ProtobufRequest decode(Channel channel, ChannelBuffer buffer) throws Exception {
		int headLen = (((int) buffer.readByte() & 0xff)) | (((int) buffer.readByte() & 0xff) << 8);
		ChannelBuffer headBuf = buffer.readBytes(headLen);
		PacketHead.Builder head = PacketHead.newBuilder().mergeFrom(new ChannelBufferInputStream(headBuf));

		if (head.hasFType() == false || ProtobufCodec.isHandlerForTypeImplement(head.getFType()) == false) {
			return null;
		}

		return new ProtobufRequest(channel, head.build(), buffer);
	}

	private ProtobufRequest(Channel channel, PacketHead head, ChannelBuffer dataBuf) throws Exception {
		this.id = head.hasFId() ? head.getFId() : null;
		this.type = head.hasFType() ? head.getFType() : null;
		this.codec = head.hasFCodec() ? head.getFCodec() : null;
		this.channel = channel;
		this.handler = ProtobufCodec.getHandlerByType(type);

		if (head.hasFCodec() && PacketCodec.clientIsGZIP(head.getFCodec())) {
			this.data = handler.getRequestType().newBuilderForType().mergeFrom(PacketCodec.decode(codec, new ChannelBufferInputStream(dataBuf))).build();
		} else {
			this.data = handler.getRequestType().newBuilderForType().mergeFrom(new ChannelBufferInputStream(dataBuf)).build();
		}
	}

	public Integer getId() {
		return id;
	}

	public Integer getCodec() {
		return codec;
	}

	public String getType() {
		return type;
	}

	public MessageLite getData() {
		return data;
	}

	public ProtobufRequestHandler getHandler() {
		return handler;
	}

	public Channel getChannel() {
		return channel;
	}

	public long getPlayerId() {
		if (channel != null) {
			SessionAccount data = (SessionAccount) channel.getAttachment();
			if (data != null) {
				return data.getUserId();
			}
		}
		return -1;
	}

	public SessionAccount getSessionAcct() {
		if (channel != null) {
			SessionAccount data = (SessionAccount) channel.getAttachment();
			return data;
		}
		return null;
	}

	public void bindSession(SessionAccount sAcct) {
		if (channel != null) {
			channel.setAttachment(sAcct);
		}
	}

	@Override
	public String toString() {
		String id_str = id == null ? "" : String.format("\"id\":%d, ", id);
		String codec_str = codec == null ? "" : String.format("\"codec\":%d, ", codec);
		return String.format("{%s%s\"type\":\"%s\", \"data\":%s}", id_str, codec_str, type, data.toString());
	}
}
